﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using System.Threading;
using dw = System.Drawing;
using System.IO;

namespace client.app.world
{
    public class MainSpace : comm.world.BObject, IBObject
    {
        public int FindTaskCount { get { return _findTaskQ.Count; } }
        public Space Space { get; private set; }
        public Ping Ping { get; private set; }
        public string UserId { get; private set; }
        public string PlayerId { get; private set; }
        public string StarId { get; private set; }
        public string SpaceId { get; private set; }
        public bool CreateSpaceComplete { get; private set; }

        public comm.objst.DStar DStar { get; private set; }
        public comm.objst.DStar.Data DStarData { get; private set; }
        public comm.objst.DStar.Data.Space DSpaceData { get; private set; }

        SpriteBatch _spriteBatch = null;
        comm.UniqueID _uid = new comm.UniqueID();
        Queue<comm.world.FindTask> _findTaskQ = new Queue<comm.world.FindTask>();
        Dictionary<string, bool> _findTaskDic = new Dictionary<string, bool>();

        Dictionary<string, comm.objst.FactionInfo> _allFactionDic = new Dictionary<string, comm.objst.FactionInfo>();

        public MainSpace()
        {
            _spriteBatch = new SpriteBatch(MainGame.Instance.GraphicsDevice);

            FindTaskInit();
        }

        void FindTaskInit()
        {
            comm.ThreadHelper.Run(() =>
            {
                while (true)
                {
                    if (_findTaskQ.Count > 0)
                    {
                        //Console.WriteLine("findQ:" + _findQ.Count);
                        var fq = _findTaskQ.Dequeue();
                        lock (_findTaskDic)
                        {
                            if (!_findTaskDic.ContainsKey(fq.Id))
                            {
                                continue;
                            }
                            else
                            {
                                _findTaskDic.Remove(fq.Id);
                            }
                        }
                        var astar = new comm.AStar();
                        var ns = astar.Find(fq.PathSize, Space.MapWidth, Space.MapHeight, fq.SX, fq.SY, fq.EX, fq.EY, Space.LocMgr.CheckPathCanEnter);
                        if (ns.Length > 0)
                        {
                            fq.Callback(comm.world.FindTaskMode.CAN_ENTER, ns);
                        }
                        else
                        {
                            ns = astar.Find(fq.PathSize, Space.MapWidth, Space.MapHeight, fq.SX, fq.SY, fq.EX, fq.EY, Space.LocMgr.CheckPathEmpty);
                            fq.Callback(comm.world.FindTaskMode.EMPTY, ns);
                        }
                    }
                    Thread.Sleep(100);
                }
            });
        }

        public void MoveView(string dir)
        {
            if (Space == null)
            {
                return;
            }
            var step = 18;
            if (dir == "left")
            {
                Space.OffsetX = Math.Min(0, Space.OffsetX + step);
            }
            else if (dir == "up")
            {
                Space.OffsetY = Math.Min(0, Space.OffsetY + step);
            }
            else if (dir == "right")
            {
                Space.OffsetX = Math.Max(MainGame.Width - Space.MapWidth * Space.MapPathSize, Space.OffsetX - step);
            }
            else if (dir == "down")
            {
                Space.OffsetY = Math.Max(MainGame.Height - Space.MapHeight * Space.MapPathSize, Space.OffsetY - step);
            }
        }
        public void MouseRightClick(int x, int y)
        {
            if (Space == null)
            {
                return;
            }
            Space.MouseRightClick(x, y);
        }
        public void SelectSObj(Rectangle rect)
        {
            if (Space == null)
            {
                return;
            }
            Space.SelectSObj(rect);
        }
        public void CancelFindTask(string id)
        {
            lock (_findTaskDic)
            {
                if (_findTaskDic.ContainsKey(id))
                {
                    _findTaskDic.Remove(id);
                }
            }
        }
        public string AddFindTask(int pathSize, int sx, int sy, int ex, int ey, Action<comm.world.FindTaskMode, comm.AStarNode[]> callback)
        {
            var id = _uid.NewId();
            var findQ = new comm.world.FindTask
            {
                Id = id,
                PathSize = pathSize,
                SX = sx,
                SY = sy,
                EX = ex,
                EY = ey,
                Callback = callback
            };
            lock (_findTaskDic)
            {
                _findTaskDic.Add(id, true);
            }
            _findTaskQ.Enqueue(findQ);
            return id;
        }
        public void Clear()
        {
            _findTaskQ.Clear();
        }

        public comm.objst.FactionInfo GetFactionInfo(string factionId)
        {
            comm.objst.FactionInfo obj = null;
            _allFactionDic.TryGetValue(factionId, out obj);
            return obj;
        }
        public comm.objst.FactionInfo[] GetAllFactionInfo()
        {
            var list = new List<comm.objst.FactionInfo>();
            foreach (var item in _allFactionDic.Values)
            {
                list.Add(item);
            }
            return list.ToArray();
        }

        public void JoinWorld(string userId, string playerId)
        {
            MainGame.MainWindow.ShowLoading("join world ...");

            UserId = userId;
            PlayerId = playerId;
            Ping = new app.Ping();
            Ping.Check(() =>
            {
                TcpClient.Call<Dictionary<string, comm.objst.FactionInfo[]>>(comm.objst.TcpMessageType.ToServerGetAllFactionDic, null, (dic, message) =>
                {
                    foreach (var infos in dic.Values)
                    {
                        foreach (var info in infos)
                        {
                            _allFactionDic.Add(info.FactionId, info);
                        }
                    }
                    MainGame.MainWindow.UpdateCahceTex();
                    TcpClient.Call(comm.objst.TcpMessageType.ToServerClientReady, null, null);
                });
            });
        }
        public void CreateSpace(string mapId, string starId, string spaceId)
        {
            StarId = starId;
            SpaceId = spaceId;
            DStar = MainGame.DefineFile.GetStar(starId);
            DStarData = MainGame.DefineFile.GetStarData(starId);

            var dSpaceId = DStar.ToRawId(spaceId);
            DSpaceData = DStarData.GetSpace(dSpaceId);

            Space = new world.Space(this, MainGame.DefineFile, mapId, starId, spaceId, DSpaceData.ObjDic);
            MainGame.MainWindow.ShowMain();
            MainGame.MainWindow.HideLoading();
            CreateSpaceComplete = true;
        }
        public void BeginDraw(comm.TimeStat timeStat)
        {
            if (Space != null)
            {
                Space.BeginDraw(timeStat);
            }
        }
        public void Draw(comm.TimeStat timeStat)
        {
            MainGame.Instance.GraphicsDevice.Clear(Color.Black);

            if (Space != null)
            {
                Space.Draw(timeStat);
            }
        }

        protected override void OnUpdate(comm.TimeStat timeStat)
        {
            if (Ping != null)
            {
                Ping.Update(timeStat);
            }

            if (Space != null)
            {
                Space.Update(timeStat);
            }
        }
    }
}
